package pp.gateway.application.video.download.impl;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import pp.gateway.application.video.download.Dto.VideosDownloadDto;
import pp.gateway.application.video.download.VideoDownloadService;
import pp.gateway.application.video.download.param.ChunkParam;
import pp.gateway.domain.video.download.VideoWriter;
import pp.infrastructure.exception.PPException;
import pp.infrastructure.exception.PPExceptionInfo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Comparator;

@Service
@Slf4j
public class VideoDownloadServiceImpl implements VideoDownloadService {
    @Value("${video.upload-dir}")
    private String uploadDir;

    @Autowired
    VideoWriter videoWriter;
    @Override
    public boolean saveChunk(ChunkParam input){
        try{
            String chunkDir = uploadDir + File.separator + input.getIdentifier();
            Path chunkPath = Paths.get(chunkDir);

            if (!Files.exists(chunkPath)) {
                Files.createDirectories(chunkPath);
            }

            String chunkFileName = input.getChunkNumber() + ".part";
            Path filePath = chunkPath.resolve(chunkFileName);
            Files.copy(input.getFile().getInputStream(), filePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            if (input.getChunkNumber() == input.getTotalChunks()-1) {
                mergeChunks(input.getIdentifier(), input.getFileName(), input.getUserId());
            }
        } catch (IOException e) {
            log.error("{}.{} --> {};", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()
                    , "分块写入异常，参数input = " + JSON.toJSONString(input));
            throw new PPException(PPExceptionInfo.GENERIC_INPUT_PARAM_INVALID);
        }
        return true;
    }

    private String mergeChunks(String identifier, String fileName, Long userId) throws IOException {
        try{
            // 基础目录
            String baseDir = uploadDir + File.separator + userId;
            Path userDirPath = Paths.get(baseDir);

            // 检查并创建用户目录
            if (!Files.exists(userDirPath)) {
                Files.createDirectories(userDirPath);
            }

            // 分块目录
            String chunkDir = uploadDir + File.separator + identifier;
            Path chunkPath = Paths.get(chunkDir);

            if (!Files.exists(chunkPath)) {
                log.error("{}.{} --> {};", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()
                        , "合并文件目录不存在，请检查");
                throw new PPException(PPExceptionInfo.GENERIC_INPUT_PARAM_INVALID);
            }

            // 获取所有分块文件并按序号排序
            File[] chunks = chunkPath.toFile().listFiles();
            System.out.println(chunks);
            if (chunks == null || chunks.length == 0) {
                log.error("{}.{} --> {};", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()
                        , "分块不存在，请检查");
                throw new PPException(PPExceptionInfo.GENERIC_INPUT_PARAM_INVALID);
            }

            // 按文件名排序
            java.util.Arrays.sort(chunks, Comparator.comparing(File::getName));

            // 创建合并后的文件
            String outputFileName = fileName + ".mp4";
            Path outputPath = userDirPath.resolve(outputFileName); // 将文件放入用户目录
            try (FileOutputStream outputStream = new FileOutputStream(outputPath.toFile())) {
                for (File chunk : chunks) {
                    Files.copy(chunk.toPath(), outputStream);
                }
            }

            // 删除分块目录
            Files.walk(chunkPath)
                    .sorted(java.util.Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);

            VideosDownloadDto dto = new VideosDownloadDto();
            dto.setFileName(fileName);
            dto.setFileSize(Files.size(outputPath));
            dto.setUserId(userId);
            dto.setFilePath(String.valueOf(outputPath));
            // 获取当前时间
            LocalDateTime now = LocalDateTime.now();

            // 将时间截断到秒
            LocalDateTime truncatedToSeconds = now.truncatedTo(ChronoUnit.SECONDS);
            dto.setUploadTime(truncatedToSeconds);
            dto.setFileType("mp4");

            if(!saveVideo(dto)){
                log.error("{}.{} --> {};", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()
                        , "文件存储异常");
                throw new PPException(PPExceptionInfo.GENERIC_INPUT_PARAM_INVALID);
            }

            return outputPath.toString();
        } catch (IOException e) {
            log.error("{}.{} --> {};", this.getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()
                    , "分块合并异常");
            throw new PPException(PPExceptionInfo.GENERIC_INPUT_PARAM_INVALID);
        }
    }

    private boolean saveVideo(VideosDownloadDto input) {
        return videoWriter.insert(input.toDO());
    }
}
